package sidecar

import (
	"io"
	"net"
	"os"
)

var logger sidecarLogger

func createSidecarLogger() error {
	logHandler, err := NewFileLogHandler("d:/debug.log", "d:/info.log", "d:/error.log")
	if err != nil {
		return err
	}
	logger = NewDafultLogger(true, true, true, logHandler)
	return nil
}

type sidecarLogger interface {
	setDebuggerEnable(b bool)
	debug(s string)
	setInfoEnable(b bool)
	info(s string)
	setErrorEnable(b bool)
	error(s string)
	startLoggerHandler()
}

type loggerHandler interface {
	handlerDebug(debugChan chan string)
	handlerInfo(infoChan chan string)
	handlerError(errorChan chan string)
}

type defaultLogger struct {
	debugChan   chan string
	infoChan    chan string
	errorChan   chan string
	debugEnable bool
	infoEnable  bool
	errorEnable bool
	logHandler  loggerHandler
}

func NewDafultLogger(debugEnable bool, infoEnable bool, errorEnable bool, logH loggerHandler) *defaultLogger {
	return &defaultLogger{
		debugChan:   make(chan string, 5000),
		infoChan:    make(chan string, 5000),
		errorChan:   make(chan string, 5000),
		debugEnable: debugEnable,
		infoEnable:  infoEnable,
		errorEnable: errorEnable,
		logHandler:  logH,
	}
}

func (l *defaultLogger) setDebuggerEnable(b bool) {
	l.debugEnable = b
}

func (l *defaultLogger) setInfoEnable(b bool) {
	l.infoEnable = b
}

func (l *defaultLogger) setErrorEnable(b bool) {
	l.errorEnable = b
}
func (l *defaultLogger) debug(s string) {
	if l.debugEnable {
		l.debugChan <- s
	}
}

func (l *defaultLogger) info(s string) {
	if l.infoEnable {
		l.infoChan <- s
	}
}

func (l *defaultLogger) error(s string) {
	if l.errorEnable {
		l.errorChan <- s
	}
}

func (l *defaultLogger) startLoggerHandler() {
	if l.debugEnable {
		go l.logHandler.handlerDebug(l.debugChan)
	}

	if l.infoEnable {
		go l.logHandler.handlerInfo(l.infoChan)
	}

	if l.errorEnable {
		go l.logHandler.handlerError(l.errorChan)
	}
}

type abstractLogHandler struct {
	debugWriter     io.Writer
	infoWriter      io.Writer
	errorWriter     io.Writer
	debugErrHandler func(s string)
	infoErrHandler  func(s string)
	errorErrHandler func(s string)
}

type fileLogHandler struct {
	abstractLogHandler
	abLH      abstractLogHandler
	debugFile string
	infoFile  string
	errorFile string
}

func NewFileLogHandler(debugPath string, infoPath string, errorPath string) (loggerHandler, error) {
	debugf, err := os.Open(debugPath)
	if err != nil {
		return nil, err
	}
	infof, err := os.Open(infoPath)
	if err != nil {
		return nil, err
	}
	errorf, err := os.Open(errorPath)
	if err != nil {
		return nil, err
	}
	return &fileLogHandler{
		debugFile: debugPath,
		infoFile:  infoPath,
		errorFile: errorPath,
		abLH: abstractLogHandler{
			debugWriter: debugf,
			infoWriter:  infof,
			errorWriter: errorf,
			debugErrHandler: func(s string) {

			},
			infoErrHandler: func(s string) {

			},
			errorErrHandler: func(s string) {

			},
		},
	}, nil
}

type netLogHandler struct {
	debugConn net.Conn
	infoConn  net.Conn
	errorConn net.Conn
	abstractLogHandler
	abLH abstractLogHandler
}

func NewNetLogHandler(debugC net.Conn, infoC net.Conn, errorC net.Conn) (*netLogHandler, error) {
	return &netLogHandler{
		debugConn: debugC,
		infoConn:  infoC,
		errorConn: errorC,
		abLH: abstractLogHandler{
			debugWriter: debugC,
			infoWriter:  infoC,
			errorWriter: errorC,
			debugErrHandler: func(s string) {

			},
			infoErrHandler: func(s string) {

			},
			errorErrHandler: func(s string) {

			},
		},
	}, nil
}

func (f *abstractLogHandler) handlerDebug(debugChan chan string) {
	for {
		s := <-debugChan
		if len(s) > 0 {
			logger.debug(s)
			_, err := f.debugWriter.Write([]byte(s))
			if err != nil {
				logger.debug("handlerDebug err" + err.Error())
				f.debugErrHandler(s)
			}
		}
	}
}

func (f *abstractLogHandler) handlerInfo(infoChan chan string) {
	for {
		s := <-infoChan
		if len(s) > 0 {
			logger.debug(s)
			_, err := f.infoWriter.Write([]byte(s))
			if err != nil {
				logger.debug("handlerInfo err" + err.Error())
				f.infoErrHandler(s)
			}
		}
	}
}

func (f *abstractLogHandler) handlerError(errorChan chan string) {
	for {
		s := <-errorChan
		if len(s) > 0 {
			logger.debug(s)
			_, err := f.errorWriter.Write([]byte(s))
			if err != nil {
				logger.debug("hanlerError err" + err.Error())
				f.errorErrHandler(s)
			}
		}
	}
}
